package com.tarena.lbs.basic.web.service;

import com.tarena.lbs.base.common.utils.Asserts;
import com.tarena.lbs.base.protocol.exception.BusinessException;
import com.tarena.lbs.basic.web.repository.UserRepository;
import com.tarena.lbs.basic.web.repository.UserTagsRepository;
import com.tarena.lbs.common.basic.util.RandomUserName;
import com.tarena.lbs.common.passport.principle.UserPrinciple;
import com.tarena.lbs.common.security.utils.LbsSecurityContenxt;
import com.tarena.lbs.pojo.basic.param.UserParam;
import com.tarena.lbs.pojo.basic.param.UserTagsParam;
import com.tarena.lbs.pojo.basic.po.UserPO;
import com.tarena.lbs.pojo.basic.po.UserTagsPO;
import com.tarena.lbs.pojo.basic.vo.UserVO;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

@Service
public class UserService {
    @Autowired
    private UserRepository userRepository;
    @Autowired
    private UserTagsRepository userTagsRepository;
    //01、用户注册
    //要做幂等，只能一个手机号去注册登录
    //1.利用手机号 做幂等判断 不能重复
    //我们要使用redis 分布式锁 同一时间只能一个线程去执行幂等操作
    public void doRegister(UserParam param) throws BusinessException {
        //对手机号加分布式锁(redis setnx),同一时间只有一个线程能够执行幂等的注册功能,其他的线程 等待|结束
        //1.利用手机号 做幂等判断 不能重复 (前台小程序的用户并发比后台高多了) 查询手机号是否存在
        String phone = param.getPhone();//从参数中获取手机号
        //注册时 判断手机号是否为存在
        boolean exists=userRepository.existsUserByPhone(phone);//true存在 false不存在
        Asserts.isTrue(exists,new BusinessException("-2","手机号已存在"));
        //2. 如果不存在则封装数据 写入数据库
        UserPO poParam=new UserPO();
        BeanUtils.copyProperties(param,poParam);/// 将参数对象的属性值复制到持久化对象中
        /*  新注册的手机号 没有绑定标签
        补充必要的属性数据 ipAddress略掉  status 0没有绑定标签 1已经绑定标签 随机人名 注册时间
         */
        poParam.setStatus(0);
        poParam.setNickName(RandomUserName.createRandomName());//随机生成用户名
        poParam.setUserName(poParam.getNickName());//昵称和用户名一致
        poParam.setRegTime(new Date());//设置注册时间
        //3.写入数据库
        userRepository.save(poParam);
    }

    // 03、小程序查询登录后的用户详情
    public UserVO detail() throws BusinessException {
        //1.获取jwt解析数据
        UserPrinciple userPrinciple = LbsSecurityContenxt.getLoginToken();
        Asserts.isTrue(userPrinciple==null,new BusinessException("-2","用户认证解析失败"));
        //2.使用userId查询数据库
        Integer id = userPrinciple.getId();
        UserPO po=userRepository.getUserById(id);
        //3.非空时封装vo返回
        po.setPassword(null);
        UserVO vo=new UserVO();
        BeanUtils.copyProperties(po,vo);
        return vo;
    }
    //04、用户绑定关联标签
    @Transactional(rollbackFor = Exception.class)
    public void bindUserTags(UserTagsParam param) throws BusinessException {
        //1.获取jwt解析数据 拿到userId
        UserPrinciple userPrinciple = LbsSecurityContenxt.getLoginToken();
        Asserts.isTrue(userPrinciple==null,new BusinessException("-2","用户认证解析失败"));
        //2.保证幂等 比如 张三 绑定 过火锅控 重新绑定选择标签 绑定 电子音乐达人 和 素食控
        Integer userId=userPrinciple.getId();
        //先删除 对应用户的标签
        userTagsRepository.deleteByUserId(userId);
        //3.封装 批量的用户标签数据 做批量写入 一次性insert多条数据 不能在业务层写for循环
        List<UserTagsPO> poParams=new ArrayList<>();
        String[] tagIds = param.getTagIds().split(",");
        for (String tagId : tagIds) {
            UserTagsPO poParam=new UserTagsPO();
            poParam.setUserId(userId);
            poParam.setTagId(Integer.valueOf(tagId));
            poParams.add(poParam);
        }
        userTagsRepository.saveBatch(poParams);
        //4.绑定标签新增成功 修改用户状态 已经绑定标签status=1
        userRepository.updateStatus(userId,1);
    }
}
